#if ENABLE_TESSELLATION

#include "CommonTessellation.cfi"

///////////////// hull shader //////////////////

struct HS_CONTROL_POINT_OUTPUT_VEGETATION
{
	hsControlPointShared controlPoint;

	float4 shadowTC : TEXCOORDN;

#if !%GRASS
	float4 Pos : TEXCOORDN;
	#if %_RT_FOG
		float4 tangVec : TEXCOORDN;
		float4 binormVec : TEXCOORDN;
	#endif
#endif

#if %LEAVES || %GRASS || %_RT_BLEND_WITH_TERRAIN_COLOR
	float4 backLight : TEXCOORDN;
#endif

#if %GRASS || (!%_RT_QUALITY && !%_RT_QUALITY1)
	float4 frontLight : TEXCOORDN;
#endif

#if %_LT_LIGHTS && %_LT_HASPROJ
	float4 projTC : TEXCOORDN;
#endif

#if %_RT_FOG
	float4 AvgFogVolumeContrib : TEXCOORDN;
#endif

#if %_RT_NOZPASS && VS_ALPHATEST
	float4 AlphaTest : TEXCOORDN;
#endif

	float4 Color0 : COLOR0;
};

HS_CONSTANT_DATA_OUTPUT VegetationConstantsHS(InputPatch<vtxOutVegetation, 3> p, uint PatchID : SV_PrimitiveID)
{
	const float3 vP0 = p[0].vView.xyz + g_VS_WorldViewPos.xyz;
	const float3 vP1 = p[1].vView.xyz + g_VS_WorldViewPos.xyz;
	const float3 vP2 = p[2].vView.xyz + g_VS_WorldViewPos.xyz;
	HS_CONSTANT_DATA_OUTPUT output = CommonConstantsHS(vP0, vP1, vP2, g_VS_WorldViewPos.xyz, g_VS_WorldViewPos.xyz, PatchID);

	return output;
}

[domain("tri")]
[partitioning("fractional_odd")]
[outputtopology("triangle_cw")]
[outputcontrolpoints(3)]
[patchconstantfunc("VegetationConstantsHS")]
[maxtessfactor(MAX_TESS_FACTOR)]
HS_CONTROL_POINT_OUTPUT_VEGETATION VegetationHS(InputPatch<vtxOutVegetation, 3> inputPatch, uint uCPID : SV_OutputControlPointID)
{
	HS_CONTROL_POINT_OUTPUT_VEGETATION	output = (HS_CONTROL_POINT_OUTPUT_VEGETATION)0;

	output.controlPoint.vView       = inputPatch[uCPID].vView;
	output.controlPoint.vNormal     = inputPatch[uCPID].vNormal.xyz;
	output.controlPoint.vBaseTC     = inputPatch[uCPID].baseTC;

	output.shadowTC   = inputPatch[uCPID].shadowTC;

#if !%GRASS
  output.Pos = inputPatch[uCPID].Pos;

  #if %_RT_FOG
    output.tangVec = inputPatch[uCPID].tangVec;
    output.binormVec = inputPatch[uCPID].binormVec;
  #endif
#endif

#if %LEAVES || %GRASS || %_RT_BLEND_WITH_TERRAIN_COLOR
  output.backLight = inputPatch[uCPID].backLight;
#endif

#if %GRASS || (!%_RT_QUALITY && !%_RT_QUALITY1)
  output.frontLight = inputPatch[uCPID].frontLight;
#endif

#if %_LT_LIGHTS && %_LT_HASPROJ
  output.projTC = inputPatch[uCPID].projTC;
#endif

  output.Color0 = inputPatch[uCPID].Color0;
  
#if %_RT_FOG
  output.AvgFogVolumeContrib = inputPatch[uCPID].AvgFogVolumeContrib;
#endif

#if %_RT_NOZPASS && VS_ALPHATEST
  output.AlphaTest = inputPatch[uCPID].AlphaTest;
#endif

	return output;
}


///////////////// domain shader //////////////////

void FillEvalInput_Vegetation(HS_CONTROL_POINT_OUTPUT_VEGETATION triPatch[3], in HS_CONSTANT_DATA_OUTPUT hsConstData, in float3 vBaryCoords, inout CommonEvaluationInputDS evalInput)
{
	evalInput.vBaryCoords = vBaryCoords;
	FillEvalInputControlPoint(triPatch[0].controlPoint, triPatch[1].controlPoint, triPatch[2].controlPoint, hsConstData, evalInput);
	evalInput.bRelativePos = true;
#if !%GRASS && %_RT_FOG
	FillEvalInputTangentBinormal(triPatch[0].tangVec, triPatch[1].tangVec, triPatch[2].tangVec, triPatch[0].binormVec, triPatch[1].binormVec, triPatch[2].binormVec, evalInput);
#endif
	FillEvalInputColor(triPatch[0].Color0, triPatch[1].Color0, triPatch[2].Color0, evalInput);
	evalInput.vViewPos = g_VS_WorldViewPos.xyz;
}

void ProcessEvalOutput_Vegetation(in CommonEvaluationOutputDS evalOutput, inout vtxOutVegetation dsOutput)
{
	dsOutput.baseTC = evalOutput.vBaseTC;
#if !%GRASS && %_RT_FOG
	dsOutput.tangVec = evalOutput.vTangent;
	dsOutput.binormVec = evalOutput.vBinormal;
#endif
	dsOutput.Color0 = evalOutput.vColor;

	dsOutput.HPosition = mul(g_VS_ViewProjZeroMatr, float4(evalOutput.vPos.xyz, 1));
}

void EvaluateVegetationSpecific(inout vtxOutVegetation output, in HS_CONTROL_POINT_OUTPUT_VEGETATION triPatch[3],
																in float3 vBaryCoords, in CommonEvaluationOutputDS evalOutput)
{
	output.shadowTC = HPosToScreenTC(output.HPosition);
	output.shadowTC.z = EvalVec(triPatch[0].shadowTC.z, triPatch[1].shadowTC.z, triPatch[2].shadowTC.z, vBaryCoords);
#if !%GRASS
	output.Pos.xyz = evalOutput.vPos.xyz;
	output.Pos.w = EvalVec(triPatch[0].Pos.w, triPatch[1].Pos.w, triPatch[2].Pos.w, vBaryCoords);
#endif
#if %LEAVES || %GRASS || %_RT_BLEND_WITH_TERRAIN_COLOR
	output.backLight = EvalVec(triPatch[0].backLight, triPatch[1].backLight, triPatch[2].backLight, vBaryCoords);
#endif

#if %GRASS || (!%_RT_QUALITY && !%_RT_QUALITY1)
	output.frontLight = EvalVec(triPatch[0].frontLight, triPatch[1].frontLight, triPatch[2].frontLight, vBaryCoords);
#endif
#if %_LT_LIGHTS && %_LT_HASPROJ
	output.projTC = EvalVec(triPatch[0].projTC, triPatch[1].projTC, triPatch[2].projTC, vBaryCoords);
#endif
#if %_RT_FOG
  output.AvgFogVolumeContrib = EvalVec(triPatch[0].AvgFogVolumeContrib, triPatch[1].AvgFogVolumeContrib, triPatch[2].AvgFogVolumeContrib, vBaryCoords);
#endif
#if %_RT_NOZPASS && VS_ALPHATEST
  output.AlphaTest = EvalVec(triPatch[0].AlphaTest, triPatch[1].AlphaTest, triPatch[2].AlphaTest, vBaryCoords);
#endif
}

[domain("tri")]
vtxOutVegetation VegetationDS( HS_CONSTANT_DATA_OUTPUT hsConstData, float3 vBaryCoords : SV_DomainLocation, const OutputPatch<HS_CONTROL_POINT_OUTPUT_VEGETATION, 3> TrianglePatch )
{
	vtxOutVegetation output = (vtxOutVegetation)0;

	CommonEvaluationInputDS evalInput = (CommonEvaluationInputDS)0;
	FillEvalInput_Vegetation(TrianglePatch, hsConstData, vBaryCoords, evalInput);

	CommonEvaluationOutputDS evalOutput;
	Evaluate(evalInput, evalOutput);
	ProcessEvalOutput_Vegetation(evalOutput, output);

	EvaluateVegetationSpecific(output, TrianglePatch, vBaryCoords, evalOutput);

	return output;
}

#endif
